/*
 * $Id: ColorHighlighter.java 4082 2011-11-15 18:39:43Z kschaefe $
 *
 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package org.jdesktop.swingx.decorator;

import static org.jdesktop.swingx.util.PaintUtils.blend;

import java.awt.Color;
import java.awt.Component;

/**
 * A Highlighter to modify component colors.
 * <p>
 * As of SwingX 1.6.1, {@code ColorHighlighter} now blends non-opaque colors.
 * This will have little effect on previous users, who were likely to be using
 * fully-opaque colors. If you are, however, supplying a non-opaque color and
 * need it to be considered opaque, use
 * {@link org.jdesktop.swingx.util.PaintUtils#removeAlpha(Color)}.
 * 
 * @author Jeanette Winzenburg
 * @author Karl Schaefer
 */
public class ColorHighlighter extends AbstractHighlighter {

	private Color background;
	private Color foreground;
	private Color selectedBackground;
	private Color selectedForeground;

	/**
	 * Instantiates a ColorHighlighter with null colors and default
	 * HighlightPredicate.
	 */
	public ColorHighlighter() {
		this(null);
	}

	/**
	 * Instantiates a ColorHighlighter with null colors and uses the specified
	 * HighlightPredicate.
	 * 
	 * @param predicate
	 *            the HighlightPredicate to use.
	 */
	public ColorHighlighter(HighlightPredicate predicate) {
		this(predicate, null, null);
	}

	/**
	 * Constructs a <code>ColorHighlighter</code> with the specified background
	 * and foreground colors and null section colors. Uses the default
	 * predicate.
	 *
	 * @param cellBackground
	 *            background color for unselected cell state
	 * @param cellForeground
	 *            foreground color for unselected cell state
	 */
	public ColorHighlighter(Color cellBackground, Color cellForeground) {
		this(null, cellBackground, cellForeground);
	}

	/**
	 * Constructs a <code>ColorHighlighter</code> with the specified unselected
	 * colors and HighlightPredicate. Initializes selected colors to null.
	 * 
	 * @param predicate
	 *            the HighlightPredicate to use.
	 * @param cellBackground
	 *            background color for unselected cell state
	 * @param cellForeground
	 *            foreground color for unselected cell state
	 */
	public ColorHighlighter(HighlightPredicate predicate, Color cellBackground, Color cellForeground) {
		this(predicate, cellBackground, cellForeground, null, null);
	}

	/**
	 * Constructs a <code>ColorHighlighter</code> with the specified background
	 * and foreground colors for unselected and selected cells. Uses the default
	 * HighlightPredicate.
	 *
	 * @param cellBackground
	 *            background color for unselected cell state
	 * @param cellForeground
	 *            foreground color for unselected cell state
	 * @param selectedBackground
	 *            background color for selected cell state
	 * @param selectedForeground
	 *            foreground color for selected cell state
	 */
	public ColorHighlighter(Color cellBackground, Color cellForeground, Color selectedBackground, Color selectedForeground) {
		this(null, cellBackground, cellForeground, selectedBackground, selectedForeground);
	}

	/**
	 * Constructs a <code>ColorHighlighter</code> with the specified colors and
	 * HighlightPredicate.
	 * 
	 * @param predicate
	 *            the HighlightPredicate to use.
	 * @param cellBackground
	 *            background color for unselected cell state
	 * @param cellForeground
	 *            foreground color for unselected cell state
	 * @param selectedBackground
	 *            background color for selected cell state
	 * @param selectedForeground
	 *            foreground color for selected cell state
	 */
	public ColorHighlighter(HighlightPredicate predicate, Color cellBackground, Color cellForeground, Color selectedBackground,
			Color selectedForeground) {
		super(predicate);
		this.background = cellBackground;
		this.foreground = cellForeground;
		this.selectedBackground = selectedBackground;
		this.selectedForeground = selectedForeground;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected Component doHighlight(Component renderer, ComponentAdapter adapter) {
		applyBackground(renderer, adapter);
		applyForeground(renderer, adapter);
		return renderer;
	}

	/**
	 * Applies a suitable background for the renderer component within the
	 * specified adapter.
	 * <p>
	 * 
	 * This implementation applies its background or selectedBackground color
	 * (depending on the adapter's selected state) if != null. Otherwise it does
	 * nothing.
	 *
	 * @param renderer
	 *            the cell renderer component that is to be decorated
	 * @param adapter
	 *            the ComponentAdapter for this decorate operation
	 */
	protected void applyBackground(Component renderer, ComponentAdapter adapter) {
		Color color = adapter.isSelected() ? getSelectedBackground() : getBackground();

		renderer.setBackground(blend(renderer.getBackground(), color));
	}

	/**
	 * Applies a suitable foreground for the renderer component within the
	 * specified adapter.
	 * <p>
	 * 
	 * This implementation applies its foreground or selectedfForeground color
	 * (depending on the adapter's selected state) if != null. Otherwise it does
	 * nothing.
	 *
	 * @param renderer
	 *            the cell renderer component that is to be decorated
	 * @param adapter
	 *            the ComponentAdapter for this decorate operation
	 */
	protected void applyForeground(Component renderer, ComponentAdapter adapter) {
		Color color = adapter.isSelected() ? getSelectedForeground() : getForeground();

		renderer.setForeground(blend(renderer.getForeground(), color));
	}

	// ---------------------- state

	/**
	 * Returns the background color of this <code>ColorHighlighter</code>.
	 *
	 * @return the background color of this <code>ColorHighlighter</code>, or
	 *         null, if no background color has been set
	 */
	public Color getBackground() {
		return background;
	}

	/**
	 * Sets the background color of this <code>ColorHighlighter</code> and
	 * notifies registered ChangeListeners.
	 * 
	 * @param color
	 *            the background color of this <code>Highlighter</code>, or
	 *            null, to clear any existing background color
	 */
	public void setBackground(Color color) {
		if (areEqual(color, getBackground()))
			return;
		background = color;
		fireStateChanged();
	}

	/**
	 * Returns the foreground color of this <code>ColorHighlighter</code>.
	 *
	 * @return the foreground color of this <code>ColorHighlighter</code>, or
	 *         null, if no foreground color has been set
	 */
	public Color getForeground() {
		return foreground;
	}

	/**
	 * Sets the foreground color of this <code>ColorHighlighter</code> and
	 * notifies registered ChangeListeners.
	 *
	 * @param color
	 *            the foreground color of this <code>ColorHighlighter</code>, or
	 *            null, to clear any existing foreground color
	 */
	public void setForeground(Color color) {
		if (areEqual(color, getForeground()))
			return;
		foreground = color;
		fireStateChanged();
	}

	/**
	 * Returns the selected background color of this
	 * <code>ColorHighlighter</code>.
	 *
	 * @return the selected background color of this
	 *         <code>ColorHighlighter</code>, or null, if no selected background
	 *         color has been set
	 */
	public Color getSelectedBackground() {
		return selectedBackground;
	}

	/**
	 * Sets the selected background color of this <code>ColorHighlighter</code>
	 * and notifies registered ChangeListeners.
	 *
	 * @param color
	 *            the selected background color of this
	 *            <code>ColorHighlighter</code>, or null, to clear any existing
	 *            selected background color
	 */
	public void setSelectedBackground(Color color) {
		if (areEqual(color, getSelectedBackground()))
			return;
		selectedBackground = color;
		fireStateChanged();
	}

	/**
	 * Returns the selected foreground color of this
	 * <code>ColorHighlighter</code>.
	 *
	 * @return the selected foreground color of this
	 *         <code>ColorHighlighter</code>, or null, if no selected foreground
	 *         color has been set
	 */
	public Color getSelectedForeground() {
		return selectedForeground;
	}

	/**
	 * Sets the selected foreground color of this <code>ColorHighlighter</code>
	 * and notifies registered ChangeListeners.
	 *
	 * @param color
	 *            the selected foreground color of this
	 *            <code>ColorHighlighter</code>, or null, to clear any existing
	 *            selected foreground color
	 */
	public void setSelectedForeground(Color color) {
		if (areEqual(color, getSelectedForeground()))
			return;
		selectedForeground = color;
		fireStateChanged();
	}
}
